package com.lmm.rpc.core.codec;

import com.lmm.rpc.core.client.protocol.MessageHeader;
import com.lmm.rpc.core.client.protocol.MessageProtocol;
import com.lmm.rpc.core.client.protocol.MessageType;
import com.lmm.rpc.core.client.protocol.ProtocolConstants;
import com.lmm.rpc.core.common.reponse.DefaultRepose;
import com.lmm.rpc.core.common.request.DefaultRequest;
import com.lmm.rpc.core.serialization.Serialization;
import com.lmm.rpc.core.serialization.SerializationFactory;
import com.lmm.rpc.core.serialization.SerializationTypeEnum;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.Data;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * 解码器
 *
 *
 *      *  自定义协议需要考虑的要素
 *      *  魔数：第一时间判断是否是无效数据
 *      *  版本号：可以支持协议升级
 *      *  序列算法：序列算法
 *      *  报文类型：登录、注册、单聊、群聊等还是其他业务
 *      *  请求序号：用于表示一条信息
 *
 *           *  +---------------------------------------------------------------+
 *      *  | 魔数 2byte | 协议版本号 1byte | 序列化算法 1byte | 报文类型 1byte|
 *      *  +---------------------------------------------------------------+
 *      *  | 状态 1byte |        消息 ID 8byte     |      数据长度 4byte     |
 *      *  +---------------------------------------------------------------+
 *      *  |                   数据内容 （长度不定）                         |
 *      *  +---------------------------------------------------------------+
 * */
@Data
public class DefaultDecoder extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Object> out) throws Exception {

        if (in.readableBytes() < ProtocolConstants.HEADER_TOTAL_LEN){
            return;
        }
        //标记读指针位置
        in.markReaderIndex();

        short magic = in.readShort();
        if (magic != ProtocolConstants.MAGIC){
            throw new IllegalArgumentException("magic is illegal " + magic);
        }

        byte version = in.readByte();
        byte serializeType = in.readByte();
        byte msgType = in.readByte();
        byte status = in.readByte();
        long requestId = in.readLong();
//        CharSequence requestId = in.readCharSequence(ProtocolConstants.REQ_LEN, StandardCharsets.UTF_8);
        int dataLen = in.readInt();

        if (in.readableBytes() < dataLen){
            //重置到之前标记的读指针位置
            in.resetReaderIndex();
            return;
        }
        byte[] data = new byte[dataLen];
        in.readBytes(data);

        MessageType messageType = MessageType.findByType(msgType);
        if (messageType == null){
            throw new IllegalArgumentException("messageType is illegal " + msgType);
        }

        MessageHeader header = new MessageHeader();
        header.setMagic(magic);
        header.setVersion(version);
        header.setSerialization(serializeType);
        header.setStatus(status);
        header.setRequestId(requestId);
        header.setMsgType(msgType);
        header.setMsgLen(dataLen);
        Serialization rpcSerialization = SerializationFactory.getRpcSerialization(SerializationTypeEnum.parseByType(serializeType));
        switch (messageType) {
            case REQUEST:
                DefaultRequest request = rpcSerialization.deserialize(data, DefaultRequest.class);
                if (request != null) {
                    MessageProtocol<DefaultRequest> protocol = new MessageProtocol<>();
                    protocol.setHeader(header);
                    protocol.setBody(request);
                    out.add(protocol);
                }
                break;
            case RESPONSE:
                DefaultRepose response = rpcSerialization.deserialize(data, DefaultRepose.class);
                if (response != null) {
                    MessageProtocol<DefaultRepose> protocol = new MessageProtocol<>();
                    protocol.setHeader(header);
                    protocol.setBody(response);
                    out.add(protocol);
                }
                break;
        }
    }
}
